package com.example.backend.service;

import com.example.backend.dto.AnnouncementDto;
import com.example.backend.entity.Announcement;
import com.example.backend.entity.User;
import com.example.backend.exception.ResourceNotFoundException;
import com.example.backend.repository.AnnouncementRepository;
import com.example.backend.repository.UserRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.stream.Collectors;

@Slf4j
@Service
@RequiredArgsConstructor
public class AnnouncementService {

    private final AnnouncementRepository announcementRepository;
    private final UserRepository userRepository;

    @Transactional
    public AnnouncementDto.Response createAnnouncement(AnnouncementDto.CreateRequest request) {
        log.info("Creating announcement with title: {}", request.getTitle());

        User author = userRepository.findById(request.getAuthorId())
                .orElseThrow(() -> new ResourceNotFoundException("作者不存在，ID: " + request.getAuthorId()));

        Announcement announcement = Announcement.builder()
                .title(request.getTitle())
                .content(request.getContent())
                .author(author)
                .priority(request.getPriority() != null ? request.getPriority() : Announcement.Priority.NORMAL)
                .isPinned(request.getIsPinned() != null ? request.getIsPinned() : false)
                .build();

        announcement = announcementRepository.save(announcement);
        log.info("Announcement created successfully with id: {}", announcement.getId());

        return mapToResponse(announcement);
    }

    @Transactional(readOnly = true)
    public AnnouncementDto.Response getAnnouncementById(Long id) {
        Announcement announcement = announcementRepository.findById(id)
                .orElseThrow(() -> new ResourceNotFoundException("公告不存在，ID: " + id));
        return mapToResponse(announcement);
    }

    @Transactional(readOnly = true)
    public Page<AnnouncementDto.Response> getAllAnnouncements(Pageable pageable) {
        return announcementRepository.findAll(pageable).map(this::mapToResponse);
    }

    @Transactional(readOnly = true)
    public Page<AnnouncementDto.Response> getAnnouncementsByStatus(
            Announcement.AnnouncementStatus status, Pageable pageable) {
        return announcementRepository.findByStatus(status, pageable).map(this::mapToResponse);
    }

    @Transactional(readOnly = true)
    public List<AnnouncementDto.Response> getPublishedAnnouncements() {
        return announcementRepository.findPublishedAnnouncementsOrderedByPinnedAndDate()
                .stream()
                .map(this::mapToResponse)
                .collect(Collectors.toList());
    }

    @Transactional(readOnly = true)
    public Page<AnnouncementDto.Response> getAnnouncementsByAuthor(Long authorId, Pageable pageable) {
        return announcementRepository.findByAuthorId(authorId, pageable).map(this::mapToResponse);
    }

    @Transactional
    public AnnouncementDto.Response updateAnnouncement(Long id, AnnouncementDto.UpdateRequest request) {
        Announcement announcement = announcementRepository.findById(id)
                .orElseThrow(() -> new ResourceNotFoundException("公告不存在，ID: " + id));

        if (request.getTitle() != null) {
            announcement.setTitle(request.getTitle());
        }

        if (request.getContent() != null) {
            announcement.setContent(request.getContent());
        }

        if (request.getStatus() != null) {
            announcement.setStatus(request.getStatus());
        }

        if (request.getPriority() != null) {
            announcement.setPriority(request.getPriority());
        }

        if (request.getIsPinned() != null) {
            announcement.setIsPinned(request.getIsPinned());
        }

        announcement = announcementRepository.save(announcement);
        log.info("Announcement updated successfully with id: {}", announcement.getId());

        return mapToResponse(announcement);
    }

    @Transactional
    public void deleteAnnouncement(Long id) {
        if (!announcementRepository.existsById(id)) {
            throw new ResourceNotFoundException("公告不存在，ID: " + id);
        }
        announcementRepository.deleteById(id);
        log.info("Announcement deleted successfully with id: {}", id);
    }

    private AnnouncementDto.Response mapToResponse(Announcement announcement) {
        User author = announcement.getAuthor();
        AnnouncementDto.AuthorInfo authorInfo = AnnouncementDto.AuthorInfo.builder()
                .id(author.getId())
                .username(author.getUsername())
                .nickname(author.getNickname())
                .avatarUrl(author.getAvatarUrl())
                .build();

        return AnnouncementDto.Response.builder()
                .id(announcement.getId())
                .title(announcement.getTitle())
                .content(announcement.getContent())
                .author(authorInfo)
                .status(announcement.getStatus())
                .priority(announcement.getPriority())
                .isPinned(announcement.getIsPinned())
                .createdAt(announcement.getCreatedAt())
                .updatedAt(announcement.getUpdatedAt())
                .build();
    }
}
